feat(sandbox): extend --share-agent-dir to Cursor, Codex, Hermes, and OpenCode#105
Open
mvanhorn wants to merge 1 commit intoInfisical:mainfrom
Open
feat(sandbox): extend --share-agent-dir to Cursor, Codex, Hermes, and OpenCode#105mvanhorn wants to merge 1 commit intoInfisical:mainfrom
mvanhorn wants to merge 1 commit intoInfisical:mainfrom
Conversation
… OpenCode The flag now picks the bind source and container mount point from the command after `--` instead of hardcoding ~/.claude. Unknown commands are rejected with a list of supported bases. knownAgents has two concepts: baseDir is the skills install directory (~/<baseDir>/skills/), stateDir is where the agent stores auth/login state. For Claude/Cursor/Hermes/OpenCode these are the same directory. For Codex they differ: skills at ~/.agents/skills/, state at ~/.codex/. The new stateDir field and effectiveStateDir() helper keep the two concepts separate so --share-agent-dir binds the real state dir. When an agent's baseDir differs from its state dir (Codex today), --share-agent-dir emits a second bind mount (~/.agents -> /home/claude/.agents) so the Agent Vault skill installed by maybeInstallSkills at ~/.agents/skills/agent-vault/SKILL.md stays visible inside the sandbox alongside the state dir. Running a non-Claude agent with --share-agent-dir requires --image: the bundled sandbox image only preinstalls @anthropic-ai/claude-code, so agent-vault now rejects that combination before launching docker run with a clear error instead of letting docker fail with "executable file not found" after the fact. Adds ContainerAgentHome/ContainerAgentConfig helpers and extends sandbox.Config with HostAgentConfig/HostAgentSkillsDir plus matching ContainerAgentDir/ContainerConfig/ContainerAgentSkillsDir fields so the existing Claude path (sibling .claude.json bind, macOS Keychain bridge, reserved-dst protection) stays intact and non-Claude agents get the same treatment without it. reservedContainerDsts now also blocks user --mount over the active skills dir. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Contributor
|
Thanks for this contribution @mvanhorn. Will take a look at this PR and review shortly :) |
7 tasks
dangtony98
added a commit
that referenced
this pull request
Apr 27, 2026
## Summary
Hard rename of `--sandbox=process|container` to
`--isolation=host|container` for `vault run`, plus the matching env var
(`AGENT_VAULT_SANDBOX` → `AGENT_VAULT_ISOLATION`) and internal package
(`internal/sandbox` → `internal/isolation`).
- **Why now**: future modes won't fit cleanly under "sandbox." Pre-1.0
is the lowest-cost moment to rename before docs/users ossify.
- **Why `host` over `process`**: today's "process" mode has no actual
process isolation — the only boundary is the agent honoring
`HTTPS_PROXY`. Naming it `host` makes the "no isolation" tradeoff
visible and nudges users toward `container` when they want a real
boundary. Also more accurate when future modes (Lima, devcontainers)
land — those run in a VM/container *from the host's perspective*.
- **No aliasing.** `--sandbox` and `AGENT_VAULT_SANDBOX` are removed,
not deprecated. Pre-1.0, the cost of a deprecation cycle outweighs the
small user impact.
- **Default behavior unchanged.** Same code paths, same security
properties, same default.
### Surfaces touched
- **Go**: `cmd/sandbox_flag.go` → `cmd/isolation_flag.go`
(`SandboxMode/Process/Container` → `IsolationMode/Host/Container`);
`internal/sandbox/` → `internal/isolation/` with embed var, image-repo
string (`agent-vault/sandbox` → `agent-vault/isolation`), host CA dir
(`~/.agent-vault/sandbox/` → `~/.agent-vault/isolation/`), and network
label (`agent-vault-sandbox` → `agent-vault-isolation`) all renamed for
consistency. Test files renamed: `internal/{mitm,ca}/sandbox_*_test.go`
→ `isolation_*_test.go`.
- **Agent skills** (versioned together per `CLAUDE.md`):
`cmd/skill_cli.md`, `cmd/skill_http.md`.
- **Docs**: `README.md`, `.env.example`, `docs/reference/cli.mdx`,
`docs/self-hosting/environment-variables.mdx`. Renamed
`docs/guides/container-sandbox.mdx` →
`docs/guides/container-isolation.mdx`; updated `docs/docs.json` nav.
`CLAUDE.md` "Two isolation modes" bullet rewritten.
`.github/dependabot.yml` docker directory path.
### One-time user impact
- Existing users will rebuild the docker image once on next `vault run
--isolation=container` use (image is hash-tagged so the old
`agent-vault/sandbox:*` orphans).
- Any pre-existing `~/.agent-vault/sandbox/` dir from prior runs becomes
orphaned (tiny PEM files; safe to `rm -rf`).
- Any orphan `agent-vault-sandbox`-labeled networks from
previously-crashed runs won't be auto-pruned.
All acceptable for a pre-1.0 hard rename; the plan accepted these
explicitly.
## Test plan
- [x] `go build ./...` — clean
- [x] `go test ./...` — all green (asset hash pin updated for the
Dockerfile comment edit)
- [x] `vault run --help` shows `--isolation` (default `host`);
`--sandbox` absent
- [x] `vault run --sandbox=process` rejected with `unknown flag:
--sandbox`
- [x] Repo-wide grep for
`AGENT_VAULT_SANDBOX|--sandbox|SandboxMode|SandboxProcess|SandboxContainer|internal/sandbox|/guides/container-sandbox`
returns zero hits
- [ ] Reviewer: check Mintlify renders
`docs/guides/container-isolation.mdx` and the nav entry
- [ ] Reviewer: rebase #105 (`feat(sandbox): extend --share-agent-dir`)
against this — its title and any flag references need updating
## Out of scope
- Adding Lima or devcontainer modes (the whole point of this rename is
to prep for those — they land in separate PRs).
- AWS SES / SocketLabs "sandbox mode" wording in `docs/guides/smtp.mdx`
(unrelated).
- Generic "sandboxed agents" SDK terminology in `README.md` and
`docs/quickstart/custom-agent.mdx` (describes external runtimes like
Daytona/E2B/Firecracker, not Agent Vault's flag).
- "vault run is a convenience wrapper, not a sandbox" sentence in
`docs/agents/overview.mdx` and `docs/guides/connect-coding-agent.mdx`
(still reads accurately for the default `host` mode).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
--share-agent-diralready listed every local agent command inknownAgents, but the container plumbing still hardcoded.claude/.claude.json. This PR wires the flag to the table so the host bind source and container mount point are derived from the command after--. Running it with an unknown command now errors out (previously silently used.claude).claude~/.claude(+~/.claude.jsonsibling, macOS Keychain bridge)/home/claude/.claudecursor/agent~/.cursor/home/claude/.cursorcodex~/.codex+~/.agents/home/claude/.codex+/home/claude/.agentshermes~/.hermes/home/claude/.hermesopencode~/.opencode/home/claude/.opencodeCodex is the one agent where the skills dir (
~/.agents, used bymaybeInstallSkillsfor the Agent Vault skill) and the state dir (~/.codex, auth/config/history) differ. TheknownAgent.stateDirfield plus aneffectiveStateDir()helper keep the two concepts separate, and the container run emits a second bind mount for~/.agentsso the Agent Vault skill stays visible inside the sandbox alongside Codex's login.The bundled sandbox image only preinstalls
@anthropic-ai/claude-code. Running a non-Claude agent on it would fail with "executable file not found" after docker run, so--share-agent-dirwith a non-Claude command now rejects early unless--imageis supplied (docs already covered this; this change moves the failure from docker's exec to a clear CLI error). The existing security invariants from #103 are preserved: Linux uid-0 refusal, HOST_UID/HOST_GID remap,reservedContainerDstscoverage (now extended to block user--mountover the active skills dir too).Pattern follows #101 for extending the agent table.
Type of change
Test plan
make test) — full suite, 16 packages greencmd/run_container_test.go:TestAgentContainerInfo_KnownAgents(covers all 5 agents including the Codex skills-vs-state split),TestAgentContainerInfo_Unknown,TestKnownAgentBases,TestRequireCustomImageForNonClaudeShare(the bundled-image gate)internal/sandbox/docker_test.go:TestBuildRunArgs_HostAgentDirCursorBindMount,TestBuildRunArgs_HostAgentDirBindMount(existing Claude regression, now using the new helpers),TestBuildRunArgs_HostAgentSkillsDirBindMount(the Codex skills dir second mount),TestBuildRunArgs_RejectUserMountActiveAgentDir,TestBuildRunArgs_RejectUserMountActiveSkillsDirgo buildproduces a working binary;./agent-vault vault run --help | grep share-agent-dirshows the updated per-agent flag description (scene 1 of the demo above)Security checklist
--share-agent-dirnow rejects unknown agent commands;BuildRunArgsrejects user--mountthat would override the active state or skills dirknownAgents, plus--imagepresenceThis contribution was developed with AI assistance.